package com.atguigu.webapp.service.impl;


import com.atguigu.common.constant.RedisConstant;
import com.atguigu.common.exception.SelfBusException;
import com.atguigu.common.result.ResultCodeEnum;
import com.atguigu.common.utils.JwtUtil;
import com.atguigu.common.utils.VerifyCodeUtil;
import com.atguigu.model.enums.BaseStatus;
import com.atguigu.model.pojo.SystemUser;
import com.atguigu.model.pojo.UserInfo;
import com.atguigu.webapp.mapper.UserInfoMapper;
import com.atguigu.webapp.service.LoginService;
import com.atguigu.webapp.service.SmsService;
import com.atguigu.webapp.service.UserInfoService;
import com.atguigu.webapp.vo.user.LoginVo;
import com.atguigu.webapp.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;


/**
 * @Author 梅超凡
 * @Date 2024/11/12~21:48
 * @Description  登录服务实现类
*/
@Service
@Slf4j
public class LoginServiceImpl implements LoginService {


    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private SmsService smsService;


    /**
     * 获取短信验证码。
     *
     * @param phone 手机号码
     * @return 操作是否成功
     * @throws SelfBusException 如果手机号码为空、发送过于频繁或其它错误
     */
    @Override
    public Boolean getSMSCode(String phone) {
        // 1. 检查手机号码是否为空
        if (!StringUtils.hasText(phone)) {
            // 如果手机号码为空，抛出自定义异常
            throw new SelfBusException(ResultCodeEnum.APP_LOGIN_PHONE_EMPTY);
        }

        // 2. 检查 Redis 中是否已经存在该手机号码的 key
        String key = RedisConstant.APP_LOGIN_PREFIX + phone;  // 生成 Redis key
        boolean hasKey = Boolean.TRUE.equals(redisTemplate.hasKey(key));  // 检查 Redis 中是否存在该 key
        if (hasKey) {
            // 若存在，则检查其存在的时间
            Long expire = redisTemplate.getExpire(key, TimeUnit.SECONDS);  // 获取 key 的剩余生存时间（秒）
            if (RedisConstant.APP_LOGIN_CODE_TTL_SEC - expire
                    < RedisConstant.APP_LOGIN_CODE_RESEND_TIME_SEC) {
                // 若存在时间不足一分钟，响应发送过于频繁
                throw new SelfBusException(ResultCodeEnum.APP_SEND_SMS_TOO_OFTEN);
            }
        }

        // 3. 发送短信，并将验证码存入 Redis
        String verifyCode = VerifyCodeUtil.getVerifyCode(6);  // 生成 6 位验证码
        smsService.sendCode(phone, verifyCode);  // 发送验证码短信
        // 4. 将验证码存入 Redis
        redisTemplate.opsForValue().set(
                key, verifyCode,  // 设置 Redis key 和验证码
                RedisConstant.APP_LOGIN_CODE_TTL_SEC,  // 设置验证码的有效时间（秒）
                TimeUnit.SECONDS);  // 设置时间单位为秒
        return true;  // 返回操作成功
    }


    @Autowired
    private UserInfoMapper userInfoMapper;  // 注入 UserInfoMapper 映射器


    /**
     * 用户登录方法。
     *
     * @param loginVo 登录信息视图对象
     * @return 生成的 JWT 令牌
     * @throws SelfBusException 如果验证码为空、手机号码为空、验证码错误、用户被禁用等
     */
    @Override
    public String login(LoginVo loginVo) {
        // 1. 判断验证码是否为空
        if (!StringUtils.hasText(loginVo.getCode())) {
            // 如果验证码为空，抛出自定义异常
            throw new SelfBusException(ResultCodeEnum.APP_LOGIN_CODE_EMPTY);
        }

        // 2. 判断手机号码是否为空
        if (!StringUtils.hasText(loginVo.getPhone())) {
            // 如果手机号码为空，抛出自定义异常
            throw new SelfBusException(ResultCodeEnum.APP_LOGIN_PHONE_EMPTY);
        }

        // 3. 判断验证码是否正确
        String key = RedisConstant.APP_LOGIN_PREFIX + loginVo.getPhone();  // 生成 Redis key
        String code = redisTemplate.opsForValue().get(key);  // 从 Redis 获取验证码

        // 判断验证码是否过期
        if (code == null) {
            // 如果验证码过期，抛出自定义异常
            throw new SelfBusException(ResultCodeEnum.APP_LOGIN_CODE_EXPIRED);
        }

        if (!loginVo.getCode().equals(code)) {
            // 如果验证码不匹配，抛出自定义异常
            throw new SelfBusException(ResultCodeEnum.APP_LOGIN_CODE_ERROR);
        }

        // 判断用户是否存在
        LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();  // 创建查询条件
        queryWrapper.eq(UserInfo::getPhone, loginVo.getPhone());  // 设置手机号码查询条件
        UserInfo userInfo = userInfoMapper.selectOne(queryWrapper);  // 查询用户信息

        if (userInfo == null) {
            // 用户不存在，创建用户
            userInfo = new UserInfo();
            userInfo.setPhone(loginVo.getPhone());  // 设置手机号码
            userInfo.setNickname("用户-" + loginVo.getPhone().substring(5));  // 设置默认昵称
            userInfoMapper.insert(userInfo);  // 插入新用户信息
        }

        // 判断用户是否被禁用
        if (userInfo.getStatus().equals(BaseStatus.DISABLE)) {
            // 如果用户被禁用，抛出自定义异常
            throw new SelfBusException(ResultCodeEnum.APP_ACCOUNT_DISABLED_ERROR);
        }

        // 创建并返回 token
        return JwtUtil.createToken(userInfo.getId(), userInfo.getPhone());  // 生成并返回 JWT 令牌
    }



    @Autowired
    private UserInfoService userInfoService;  // 注入 UserInfoService 服务
    /**
     * 根据用户 ID 获取登录用户的详细信息。
     *
     * @param userId 用户 ID
     * @return 用户信息视图对象
     */
    @Override
    public UserInfoVo getLoginUserInfoById(Long userId) {
        // 通过 UserInfoService 获取用户信息
        UserInfo userInfo = userInfoService.getById(userId);

        // 创建 UserInfoVo 对象，传入昵称和头像 URL
        UserInfoVo userInfoVo = new UserInfoVo(userInfo.getNickname(), userInfo.getAvatarUrl());

        // 记录日志，输出登录信息
        log.info("登录信息：{}", userInfoVo);

        // 返回用户信息视图对象
        return userInfoVo;
    }

}
